﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Flexible.Implementions.Attributes;
using Flexible.Implementions.Helpers;
using Flexible.Interfaces;

namespace Flexible.Implementions.Bases
{
    [Plugin]
    public abstract class PluginBase : IPlugin
    {
        public PluginBase()
        {
            signature = new PluginSignature(Id, Name, Description, Author, Version, ReleaseTime, CompatibleVersion, Requirements, Interests);
            settings = new Dictionary<IUserSetting, PropertyInfo>();

            foreach (var property in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                UserSettingAttribute attrib = Attribute.GetCustomAttribute(property, typeof(UserSettingAttribute), true) as UserSettingAttribute;
                if (attrib != null)
                {
                    object defaultValue = Converter.ConvertTo(attrib.DefaultValue, property.PropertyType);

                    ISettingEditor editor;
                    SettingEditorAttribute editorAttrib = Attribute.GetCustomAttribute(property, typeof(SettingEditorAttribute)) as SettingEditorAttribute;
                    if (editorAttrib != null)
                    {
                        editor = editorAttrib.GetEditor();
                    }
                    else
                    {
                        editor = SettingEditors.GetDefaultEditor(property.PropertyType);
                    }

                    UserSetting setting = new UserSetting(attrib.Name, attrib.Description, attrib.Category, property.PropertyType, defaultValue, editor);
                    settings.Add(setting, property);
                }
            }
        }

        #region IPlugin Members

        public virtual IPluginSignature Signature
        {
            get { return signature; }
        }

        public abstract void Enable(IPluginActivateContext context);

        public abstract void Disable(IPluginActivateContext context);

        public virtual IEnumerable<IUserCommand> Commands
        {
            get { yield break; }
        }

        public virtual void InsterestedPluginEnabled(string id, IPlugin plugin)
        {
        }

        public virtual void InsterestedPluginDisabling(string id, IPlugin plugin)
        {
        }

        public virtual IEnumerable<IUserSetting> GetAiailableSettings()
        {
            return settings.Keys;
        }

        public virtual object GetSettingValue(IUserSetting setting)
        {
            PropertyInfo pi = settings[setting];
            return pi.GetValue(this, null);
        }

        public virtual void SetSettingValue(IUserSetting setting, object value)
        {
            PropertyInfo pi = settings[setting];
            pi.SetValue(this, value, null);
        }

        public virtual void SaveSettings(Stream output)
        {
            StreamWriter writer = new StreamWriter(output, Encoding.UTF8);
            foreach (var setting in settings.Keys)
            {
                setting.SettingEditor.Value = GetSettingValue(setting);
                writer.WriteLine(string.Format("{0}={1}", setting.Name, setting.SettingEditor.ToStringFormat()));
            }
            writer.Flush();
        }

        public virtual void LoadSettings(Stream input)
        {
            Dictionary<string, IUserSetting> total = new Dictionary<string, IUserSetting>();
            settings.Keys.ForEach(x => total.Add(x.Name, x));

            Dictionary<IUserSetting, object> result = new Dictionary<IUserSetting, object>();

            StreamReader reader = new StreamReader(input, Encoding.UTF8);
            for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
            {
                line = line.Trim();
                if (line.Length > 0)
                {
                    int indexOfEqual = line.IndexOf('=');
                    if (indexOfEqual > 0)
                    {
                        string id = line.Substring(0, indexOfEqual);
                        string value = line.Substring(indexOfEqual + 1);

                        IUserSetting setting = total[id];
                        setting.SettingEditor.Value = value;

                        if (setting.SettingEditor.IsValid)
                        {
                            result.Add(setting, setting.SettingEditor.Value);
                        }
                        else
                        {
                            result.Add(setting, setting.DefaultValue);
                        }
                        total.Remove(id);
                    }
                }
            }

            foreach (var rest in total)
            {
                var setting = rest.Value;
                setting.SettingEditor.Value = setting.DefaultValue;
                result.Add(setting, setting.DefaultValue);
            }

            result.ForEach(x => SetSettingValue(x.Key, x.Value));

        }

        #endregion

        #region signature
        PluginSignature signature;

        public virtual IEnumerable<IPluginQuery> Requirements
        {
            get { yield break; }
        }

        public virtual IEnumerable<IPluginQuery> Interests
        {
            get { yield break; }
        }

        public abstract string Name
        {
            get;
        }

        public abstract string Description
        {
            get;
        }

        public abstract string Author
        {
            get;
        }

        public abstract DateTime ReleaseTime
        {
            get;
        }

        public abstract string Id
        {
            get;
        }

        public abstract Version Version
        {
            get;
        }

        public abstract Version CompatibleVersion
        {
            get;
        }
        #endregion

        Dictionary<IUserSetting, PropertyInfo> settings;

    }
}
